﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Enyim.Caching;
using Enyim.Caching.Memcached;
using Framework.Zhaogang.Cache.Core;

namespace Framework.Zhaogang.Cache.Memcached
{
    /// <summary>
    /// 远程缓存管理器
    /// </summary>
    public class MemcachedCacheManager : ICacheManager
    {

        #region Ctors

        /// <summary>
        /// 
        /// </summary>
        /// <param name="bucket"></param>
        public MemcachedCacheManager(string bucket)
        {
            RegionName = bucket;
            memcachedClient = new MemcachedClient();
        }

        #endregion

        #region Properties

        /// <summary>
        /// 区块
        /// </summary>
        public string RegionName { get; private set; }

        #endregion

        #region Fields

        IMemcachedClient memcachedClient;

        #endregion

        #region Methods

        /// <summary>
        /// 覆盖（原子操作）
        /// </summary>
        /// <param name="key"></param>
        /// <param name="value"></param>
        /// <param name="isAbsoluteExpire"></param>
        /// <param name="expireMinutes"></param>
        public bool Set(string key, object value, bool isAbsoluteExpire = true, int expireMinutes = 0)
        {
            var cas = new CasResult<object>();
            var casResult = memcachedClient.TryGetWithCas(MergeKey(key), out cas);
            var setCasResult = default(CasResult<bool>);

            if (isAbsoluteExpire)
            {
                if (expireMinutes > 0)
                {
                    setCasResult = memcachedClient.Cas(StoreMode.Set, MergeKey(key), value, DateTime.Now.AddMinutes(expireMinutes), cas.Cas);
                }
                else
                {
                    setCasResult = memcachedClient.Cas(StoreMode.Set, MergeKey(key), value, cas.Cas);
                }
            }
            else
            {
                if (expireMinutes > 0)
                {
                    setCasResult = memcachedClient.Cas(StoreMode.Set, MergeKey(key), value, TimeSpan.FromMinutes(expireMinutes), cas.Cas);
                }
                else
                {
                    setCasResult = memcachedClient.Cas(StoreMode.Set, MergeKey(key), value, cas.Cas);
                }
            }
            return setCasResult.Result;
        }

        /// <summary>
        /// 获取
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key"></param>
        /// <returns></returns>
        public T Get<T>(string key)
        {
            return memcachedClient.Get<T>(MergeKey(key));
        }

        /// <summary>
        /// 是否存在键
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public bool HasKey(string key)
        {
            var obj = new object();
            return memcachedClient.TryGet(MergeKey(key), out obj);
        }

        /// <summary>
        /// 移除
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public object Remove(string key)
        {
            var obj = new object();
            var getResult = memcachedClient.TryGet(MergeKey(key), out obj);
            if (getResult)
            {
                memcachedClient.Remove(MergeKey(key));
            }
            return obj;
        }

        /// <summary>
        /// 根据条件模糊查询（未实现）
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="expression"></param>
        /// <param name="keyParam"></param>
        /// <returns></returns>
        public IEnumerable<T> Where<T>(Func<T, bool> expression, string keyParam = "")
        {
            return default(IEnumerable<T>);
        }

        #endregion

        #region Private Methods

        /// <summary>
        /// 合并键
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        private string MergeKey(string key)
        {
            return RegionName + "_" + key;
        }

        #endregion
    }
}
